home *** CD-ROM | disk | FTP | other *** search
/ C/C++ Users Group Library 1996 July / C-C++ Users Group Library July 1996.iso / vol_400 / 425_01 / tar / restore.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-04-02  |  15.2 KB  |  571 lines

  1. /* restore.c - extract regular files from (tape) archive.
  2.  * This is a part of the Tar program (see file tar.c)
  3.  * Author: T.V.Shaporev
  4.  * Creation date: 11 Mar 1993
  5.  */
  6. #include <stdio.h>
  7. #include <errno.h>
  8.  
  9. #include "sysup.h"
  10. #include "modern.h"
  11. #ifdef MODERN
  12. #    include <string.h>
  13. #else
  14.     char *strncpy();
  15.     int  strlen();
  16. #endif
  17.  
  18. #ifdef MSDOS
  19. #    include <io.h>
  20. #    include <dos.h>
  21. #    include <stdlib.h>
  22. #    ifdef __TURBOC__
  23. #        include <dir.h>
  24. #    else
  25. #        include <direct.h>
  26. #    endif
  27. #else
  28.     int  access(), creat(), open(), close(), link(), unlink();
  29.     int  write(), chown(), utime();
  30.     char *malloc();
  31.         long lseek();
  32.     void free();
  33. #endif
  34.  
  35. #include "lzwbits.h"
  36. #include "lzwhead.h"
  37. #include "compress.h"
  38. #include "define.h"
  39. #include "lzpack.h"
  40.  
  41. char ofname[MAXTNAME
  42. #ifdef MSDOS
  43.             +MAXFILE
  44. #endif
  45.             +1];
  46.  
  47. void extwrerr()
  48. {
  49.    (void)fprintf(myout, "Tar: error extracting \'%s\'\n", ofname);
  50.    done(EWRITE);
  51. }
  52.  
  53. #ifdef MSDOS
  54. static void setime __ARGS__(( int, long ));
  55.  
  56. static void setime(h, mt)
  57. int h; long mt;
  58. {
  59.    struct date d;
  60.    struct time t;
  61.    struct ftime f;
  62.  
  63.    if (m_flag) return;
  64.    unixtodos(mt, &d, &t);
  65.    f.ft_tsec  = t.ti_sec;
  66.    f.ft_min   = t.ti_min;
  67.    f.ft_hour  = t.ti_hour;
  68.    f.ft_day   = d.da_day;
  69.    f.ft_month = d.da_mon;
  70.    f.ft_year  = d.da_year - 1980;
  71.    (void)setftime(h, &f);
  72. }
  73.  
  74. #define wcnt_type unsigned short
  75. #define MAXWARN  8
  76.  
  77. static renamed = FALSE;
  78. static wcnt_type wcount = 0;
  79. static nwarn = 0;
  80.  
  81. static struct { wcnt_type lru; char wnm[MAXTNAME]; } wlist[MAXWARN];
  82.  
  83. static void wrename __ARGS__(( char * ));
  84.  
  85. static void wrename(n)
  86. char *n;
  87. {
  88.    register i;
  89.  
  90.    renamed = FALSE;
  91.    for (i=0; i<nwarn; i++) {
  92.      if (strncmp(wlist[i].wnm, n, MAXTNAME) == 0) {
  93.         wlist[i].lru = wcount++; return;
  94.      }
  95.    }
  96.    (void)printf("Tar: warning: renamed to \'%s\'\n", n);
  97.    if (nwarn < MAXWARN) {
  98.       i = nwarn++;
  99.    } else {
  100.       register j;
  101.       /* Find the least recently used entry */
  102.       for (i=0, j=1; j<MAXWARN; j++) {
  103.          if (wlist[j].lru < wlist[i].lru) i = j;
  104.       }
  105.    }
  106.    (void)strncpy(wlist[i].wnm, n, MAXTNAME);
  107.    wlist[i].lru = wcount++;
  108. }
  109.  
  110. #define CH_DOT '-'
  111. #define CH_BAD '$'
  112.  
  113. static void uname __ARGS__(( char * ));
  114.  
  115. static void uname(fname) /* convert UNIX file name to DOS */
  116. char fname[];
  117. {
  118.    static char invalid[] = "^+=/[]:;\',?*\\<>|\".";
  119.    register char *p = fname;
  120.    register i, offext/* offset to file name extension */;
  121.    register j, limcpy, tmpren;
  122.  
  123.    if (p[1] == ':' && (p[0]>='A' && p[0]<='Z' || p[0]>='a' && p[0]<='z'))
  124.       p += 2;
  125.  
  126.    tmpren = FALSE;
  127.    while (*p) {
  128.       if (*p == '/') {
  129.          ++p; /* Forget dir name changes */ tmpren = FALSE;
  130.       }
  131.  
  132.       for (offext=i=0; p[i] && p[i]!='/'; i++) {
  133.          if (p[i] == '.') {
  134.             if (i == 0) {
  135.                if (p[1]=='.' && p[2]=='/') {
  136.                   /* This is '..' directory, skip */ ++i;
  137.                } else if (p[1]!='/') {
  138.                   /* This is not current directory */
  139.                   p[0] = CH_DOT; tmpren = TRUE;
  140.                }
  141.             } else {
  142.                if (offext) {
  143.                   p[offext] = CH_DOT; tmpren = TRUE;
  144.                }
  145.                offext = i;
  146.             }
  147.          } else if (p[i]<=' ' || p[i]>'~' || strchr(invalid, p[i])) {
  148.             p[i] = CH_BAD; tmpren = TRUE;
  149.          }
  150.       }
  151.       if (!offext) offext = i;
  152.       limcpy = MAXTNAME - (int)(p-fname) - offext;
  153.       i -= offext;
  154.       if (offext <= 8) {
  155.          j = offext;
  156.       } else {
  157.          (void)strncpy(p+8, p+offext, i>4 ? 4 : limcpy);
  158.          tmpren = TRUE;
  159.          j = 8;
  160.       }
  161.       if (i <= 4) {
  162.          j += i;
  163.       } else {
  164.          (void)strncpy(p+(offext>8 ? 12 : offext+4), p+i+offext, limcpy-i);
  165.          tmpren = TRUE;
  166.          j += 4;
  167.       }
  168.       p += j;
  169.    }
  170.    if (tmpren) renamed = TRUE;
  171. }
  172. #else
  173. #    define setime(h,t)
  174. #    define uname(s)
  175. #endif
  176.  
  177. int makedir __ARGS__((char *, int));
  178. int testdir __ARGS__((char *));
  179.  
  180. /*ARGSUSED*/ int makedir(p, to_print)
  181. char *p; int to_print;
  182. {
  183. #ifdef UNIX
  184. #   ifdef RMKDIR
  185.          if (mkdir(p, 0777) != 0 && to_print) {
  186.             (void)fprintf(myout, "Tar: can\'t create directory \'%s\'\n", p);
  187.             return ERROR;
  188.          }
  189. #   else
  190.          switch (bincall("mkdir", p)) {
  191.             case  0: break;
  192.             case -1: (void)fprintf(myout, "Tar: fault run mkdir!\n");
  193.             default: done(0);
  194.          }
  195. #   endif
  196.          if (!o_flag) (void)chown(p,(int)st.st_uid,(int)st.st_gid);
  197. #endif
  198. #ifdef MSDOS
  199.          if (mkdir(p) != 0 && to_print) {
  200.             (void)fprintf(myout, "Tar: can\'t create directory \'%s\'\n", p);
  201.             return ERROR;
  202.          }
  203. #endif
  204.    return 0;
  205. }
  206.  
  207. int testdir(p)
  208. char *p;
  209. {
  210.    register j;
  211.    register k = FALSE;
  212. #ifndef UNIX
  213.    register char *q = p;
  214. #endif
  215. #ifdef MSDOS
  216.    renamed = FALSE;
  217. #endif
  218.    for (j=1; j<MAXTNAME && p[j]; j++) {/* check directories */
  219.       if (p[j] == '/') {
  220.          p[j] = 0;
  221. #ifndef UNIX
  222.          uname(q); q = p + j + 1;
  223. #endif
  224.          if (access(p, 1) < 0) {
  225.             if (makedir(p, TRUE) != 0) return ERROR;
  226.             k = TRUE;
  227.          }
  228.          p[j] = '/';
  229.       }
  230.    }
  231. #ifdef MSDOS
  232.    if (renamed && v_flag) wrename(p);
  233. #endif
  234.    return k;
  235. }
  236.  
  237. long thisread;
  238.  
  239. int arcget __ARGS__((void))
  240. {
  241.    if (v_flag && !(thisread & 07777)) percent(thisread, st.st_size);
  242.    return thisread<st.st_size ? (++thisread, readbyte()) : EOF;
  243. }
  244.  
  245. static int  o_file, indput;
  246. static long thiscsum;
  247.  
  248. static void dstput(c)
  249. int c;
  250. {
  251.    thiscsum += c; ((unsigned char *)pk_out)[indput++] = c;
  252.    if (indput >= pksize) {
  253.       if (write(o_file, pk_out, pksize) != pksize) {
  254.          if (v_flag) (void)fprintf(myout, "\n");
  255.          extwrerr();
  256.       }
  257.       indput = 0;
  258.    }
  259. }
  260.  
  261. #define savename(s) ((void)strncpy(ofname,(s),MAXTNAME),ofname[MAXTNAME]='\0')
  262.  
  263. static int newfile __ARGS__(( char *, int ));
  264.  
  265. static int newfile(name, mode)
  266. char *name; int mode;
  267. {
  268. #ifdef MSDOS
  269.    int h, caccess;
  270.    unsigned cmode;
  271.    register k = 0;
  272.  
  273.    savename(name);
  274.    caccess = o_flag ? O_CREAT+O_EXCL+O_WRONLY+O_BINARY :
  275.                       O_CREAT+O_TRUNC+O_WRONLY+O_BINARY;
  276.    cmode = (mode & 0444 ? S_IREAD  : 0) |
  277.            (mode & 0222 ? S_IWRITE : 0) |
  278.            (mode & 0111 ? S_IEXEC  : 0);
  279.    if ((h = open(name, caccess, cmode)) < 0) {
  280.       if (errno == ENOENT || errno == ENOPATH) {
  281.          if ((k=testdir(name)) == TRUE) h = open(name, caccess, cmode);
  282.       } else if (errno == EEXIST && o_flag) {
  283.          static char del[4] = "^~\'`";
  284.          register unsigned ntry = 0;
  285.          register nb, len, i, j;
  286.          char suffix[5];
  287.  
  288.          if ((len = strlen(name)) > MAXTNAME) goto end;
  289.          for (nb=len; nb>0 && name[nb-1]!='/' && name[nb-1]!=':'; nb--) {
  290.             if (name[nb] == '.') len = nb;
  291.          }
  292.          len -= nb;
  293.          do {
  294.             ++ntry;
  295.             /* Convert number of try into suffix */
  296.             suffix[0] = del[ntry & 3];
  297.             for (i=1, j=ntry>>2; j; j>>=5) {
  298.                suffix[i++] = ((j & 037) < 10 ? '0': 'A'-10) + (j & 037);
  299.             }
  300.             suffix[i] = '\0';
  301.             /* Replace end of the name by suffix */
  302.             if (len < 8) {
  303.                (void)strcat(
  304.                         strcpy(ofname+nb+(len+i<8 ? len : 8-i), suffix),
  305.                         name+nb+len);
  306.             } else {
  307.                (void)strncpy(ofname+nb+len-i, suffix, i);
  308.             }
  309.             renamed = TRUE;
  310.             h = open(ofname, caccess, cmode);
  311.          } while (h<0 && errno == EEXIST && ntry);
  312.       }
  313.    }
  314. end:
  315.    if (h < 0) {
  316.       if (k!=ERROR) (void)fprintf(myout,"Tar: can\'t create \'%s\'\n",name);
  317.    } else {
  318.       if (renamed && v_flag) wrename(ofname);
  319.       if ((mode & 0777) == 0) (void)_chmod(name, 1, FA_HIDDEN);
  320.    }
  321.    return h;
  322. #else
  323.    register j = 0;
  324.    register h;
  325.  
  326.    savename(name);
  327.    do {
  328.       if ((h = creat(name, (int)(mode & 07777))) >= 0) {
  329.          if (!o_flag) (void)chown(name, (int)st.st_uid, (int)st.st_gid);
  330.          return h;
  331.       }
  332.    } while (++j < 2 && testdir(name) == TRUE);
  333.  
  334.    if (j > 1) (void)fprintf(myout, "Tar: can\'t create \'%s\'\n", name);
  335.    return ERROR;
  336. #endif
  337. }
  338.  
  339. static void pfile __ARGS__((char *, long, long));
  340.  
  341. static void pfile(name, bytes, blocks)
  342. char name[]; long bytes, blocks;
  343. {
  344.    if (v_flag) {
  345.       (void)fprintf(myout, "x %s, %ld bytes, %ld tape blocks",
  346.                     name, bytes, blocks);
  347.       (void)fflush(myout);
  348.    }
  349. }
  350.  
  351. static int xany __ARGS__((void))
  352. {
  353.    (void)fprintf(stderr, " Extract anyway? ");
  354.    (void)fflush(stderr);
  355.    return YES_NO();
  356. }
  357.  
  358. int restore(p)
  359. register char *p;
  360. {
  361.    register j;
  362.  
  363.    register long bytes, blocks;
  364.    static char no_mem[] = "\nTar: no memory to unpack.";
  365.    static char e[] = "    \n";
  366.    short nx=0, allx; long l=0, xinfo;
  367.    int multy = FALSE; /* Multyvolume processing flag */
  368.    extern int soctul __ARGS__((char*, long*));
  369. #ifdef MSDOS
  370.    renamed = FALSE;
  371. #endif
  372.    if (hblock->filetype == GF_MUL) {
  373.       (void)soctul(hblock->x.new.offset, &xinfo);
  374.       multy = TRUE;
  375.    } else {
  376.       if ((nx = isextent(&allx, &xinfo)) > 0) multy = TRUE;
  377.    }
  378.    bytes  = codesize > st.st_size ? codesize : st.st_size;
  379.    blocks = (st.st_size + BLKSIZE-1)/BLKSIZE;
  380.    if (pktype == PKfLZW && !multy && st.st_size >= codesize) {
  381.       j = strlen(p);
  382.       if (p[--j] != 'Z' || p[--j] != '.') goto regular;
  383.       p[j] = '\0';
  384.       uname(p);
  385.       if ((o_file = newfile(p, st.st_mode)) < 0) {
  386.          skipfile(); return ERROR;
  387.       }
  388.       pfile(p, bytes, blocks);
  389.       p[j] = '.';
  390.       (void)z_getmem(BITS);
  391.       thisread = 0; indput = 0; thiscsum = 0;
  392.       if ((j = dbegin(arcget)) == 0) {
  393.          do {
  394.             j = dpiece(pk_out, pksize);
  395.             if (j > 0) {
  396.                if (write(o_file, pk_out, j) != j) {
  397.                   if (v_flag) (void)fprintf(myout, "\n");
  398.                   extwrerr();
  399.                }
  400.                if (v_flag) percent(thisread, st.st_size);
  401.             }
  402.          } while (j == pksize);
  403.          (void)fprintf(myout, v_flag ? e : e+sizeof(e)-2);
  404.          goto xend;
  405.       } else if (j > 0) {
  406.          if (v_flag) (void)fprintf(myout, " is not in compressed format\n");
  407.       } else {
  408.          if (!xany()) done(ESMALL);
  409.       }
  410.       bacouple(); z_relmem();
  411.    }
  412. regular:
  413.    uname(p);
  414.    if (nx > 1 || (hblock->filetype == GF_MUL && xinfo > 0)) {
  415.       /* Multivolume processing */
  416.       if ((o_file = open(p, O_WRONLY|O_BINARY)) >= 0) {
  417.          savename(p);
  418.          if ((l=lseek(o_file, 0L, 2)) == -1L) {
  419.             (void)fprintf(myout, " Tar: \'%s\' seek error\n", p);
  420.             goto fault;
  421.          }
  422.          if (hblock->filetype == GF_MUL && l != xinfo) {
  423.             if (w_flag) {
  424.                (void)fprintf(stderr,
  425.                   " Tar: \'%s\' mismatch size. Append? ", p);
  426.                (void)fflush(stderr);
  427.                if (YES_NO()) goto opened;
  428.             } else {
  429.                (void)fprintf(myout,
  430.                   " Tar: warning: \'%s\' mismatch size\n", p);
  431.             }
  432.             l = lseek(o_file, xinfo, 0);
  433.          }
  434.          goto opened;
  435.       } else if (errno == ENOENT) {
  436.          if (w_flag) {
  437.             (void)fprintf(stderr,
  438.                " Tar: \'%s\' does not exist.", p);
  439.             if (!xany()) goto fault;
  440.          } else {
  441.             (void)fprintf(myout,
  442.                " Tar: warning: \'%s\' does not exist\n", p);
  443.             goto fault;
  444.          }
  445.       } else {
  446.          (void)fprintf(myout, "Tar: can\'t append \'%s\'\n", p);
  447.          goto fault;
  448.       }
  449.    }
  450.    if ((o_file = newfile(p, st.st_mode)) < 0) goto fault;
  451. opened:
  452.    pfile(ofname, bytes, blocks);
  453.  
  454.    if (st.st_size >= codesize || multy) {/* file was not packed */
  455.       if (v_flag) {
  456.          if (nx > 0) {
  457.             (void)fprintf(myout," [extent #%d of %d]", nx, allx);
  458.          } else if (hblock->filetype == GF_MUL) {
  459.             (void)fprintf(myout," [");
  460.             if (l != xinfo)
  461.                (void)fprintf(myout,"from %ld - ", xinfo);
  462.             (void)fprintf(myout,"append @%ld]", l);
  463.          }
  464.          (void)fprintf(myout, "\n");
  465.       }
  466.       (void)readarch(o_file, st.st_size);
  467.       if (nx > 1 && nx == allx && lseek(o_file, 0L, 2) != xinfo) {
  468.          /* last extent extracted, so check for total file size */
  469.          (void)fprintf(myout,"Tar: warning: \'%s\' changed size\n",ofname);
  470.       }
  471.    } else {/* file was packed */
  472.       if (!pk_out) pk_out = malloc(pksize);
  473.       if (!pk_out || lzgetmem()) {
  474.          (void)fprintf(myout, "%s\n", no_mem);
  475.          done(ESMALL);
  476.       }
  477.       thisread = 0; indput = 0; thiscsum = 0;
  478.  
  479.       l = lzdecode(arcget, dstput, codesize);
  480.       (void)fprintf(myout, v_flag ? e : e+sizeof(e)-2);
  481.       if (indput > 0 && write(o_file, pk_out, indput) != indput)
  482.          extwrerr();
  483.       if (l != codesize) {
  484.          (void)fprintf(myout, "Tar: \'%s\' decode error\n", ofname);
  485.          if (!i_flag) done(EINTER);
  486.       }
  487.       if (thiscsum != longcsum) {
  488.          (void)fprintf(myout, "Tar: \'%s\' checksum error\n", ofname);
  489.       }
  490.    }
  491. xend:
  492.    j = nx > 0 && nx < allx;
  493. #ifdef MSDOS
  494.    if (!j) setime(o_file, st.st_mtime);
  495. #endif
  496.    (void)close(o_file);
  497.    return j;
  498. fault:
  499.    if (o_file >= 0) (void)close(o_file);
  500.    skipfile();
  501.    return ERROR;
  502. }
  503.  
  504. void makelink(fname, lname)
  505. char *fname, *lname;
  506. {
  507. #ifdef MSDOS
  508. #  define BUFSIZE 8192
  509.    char *buffer = NULL;
  510.    int bufsize = BUFSIZE;
  511. #endif
  512.    register j;
  513.  
  514. #ifdef UNIX
  515.    (void)unlink(fname);
  516.    if ((j = link(lname, fname)) < 0) {
  517.       if (testdir(fname) == TRUE) j = link(lname, fname);
  518.    }
  519.    if (j < 0)
  520.       (void)fprintf(myout,
  521.          "Tar: can\'t link \'%s\' to \'%s\'\n", fname, lname);
  522.    else
  523. #endif
  524. #ifdef MSDOS
  525.    if (l_flag) {/* copy file */
  526.       int inp, out;
  527.       char *buffer; int bufsize;
  528.       long rsize, mtime;
  529.  
  530.       if ((buffer = malloc(BUFSIZE)) == NULL) {
  531.          if (pk_out) {
  532.             buffer = pk_out;
  533.             bufsize = pksize;
  534.          } else {
  535.             buffer = (char *)hblock;
  536.             bufsize = BLKSIZE;
  537.          }
  538.       }
  539.       if ((inp = open(lname, O_RDONLY+O_BINARY)) < 0) {
  540.          cantopen(lname); goto quit;
  541.       }
  542.       if ((out = newfile(fname, st.st_mode)) < 0) {
  543.          (void)close(inp); goto quit;
  544.       }
  545.       rsize = st.st_size;
  546.       mtime = st.st_mtime;
  547.       do {
  548.          if ((j = read(inp, buffer, bufsize)) > 0) {
  549.             rsize -= j;
  550.             if (write(out, buffer, j) != j) {
  551.                extwrerr(); j = ERROR;
  552.             }
  553.          }
  554.       } while (j == bufsize);
  555.       if (j >= 0) setime(out, mtime);
  556.       (void)close(out);
  557.       (void)close(inp);
  558.       if (j < 0) goto quit;
  559.       if (v_flag) (void)fprintf(myout, "x %s copied from %s\n", fname, lname);
  560.       if (rsize != 0)
  561.          (void)fprintf(myout,
  562.             "Tar: warning \'%s\' real size differs from the recorded\n",fname);
  563.    } else
  564. #endif
  565.    if (v_flag) (void)fprintf(myout, "x %s linked to %s\n", fname, lname);
  566. #ifdef MSDOS
  567. quit:
  568.    if (buffer != NULL && bufsize == BUFSIZE) free(buffer);
  569. #endif
  570. }
  571.